﻿// -------------------------------------------------------------------------
//    @FileName         :    NFStorageBagOpMgr.cpp
//    @Author           :    Gao.Yi
//    @Date             :    2025-10-21
//    @Email			:    445267987@qq.com
//    @Module           :    NFStorageBagOpMgr
//    @Desc             :
//
// -------------------------------------------------------------------------

// --- 文件总结 ---------------------------------------------------------------
// 本文件实现 NFStorageBagOpMgr 类的功能：
// 
// 【构造/析构】
// - NFStorageBagOpMgr：初始化仓库背包操作管理器，自动添加仓库页签
// - ~NFStorageBagOpMgr：析构函数
// 
// 【提交和同步】
// - Commit：提交所有仓库背包变更，同步到客户端，触发事件
// - CommitToPlayer：预检查、提交背包页签、触发物品增删事件
// - SyncToPlayer：同步仓库背包变更到客户端
// - PreCheckCommit：预检查提交前的状态
// - SyncPackageToPlayer：将仓库背包变更同步给所有角色
// 
// 【背包管理】
// - GetBagPage：获取仓库背包页签
// - AddAllBagPage：添加仓库背包页签（EN_BPT_STORAGE）
// 
// 【金钱操作】（仓库不支持金钱，所有金钱操作返回错误或0）
// - GetMoneyNumber：返回0
// - SetMoneyNumber：返回 ERR_CODE_INVALID_REQ_PARAM
// - IncMoney：返回 ERR_CODE_INVALID_REQ_PARAM
// - DecMoney：返回 ERR_CODE_INVALID_REQ_PARAM
// 
// 【特殊处理】
// - AddItemWhenBagFull：背包满时的处理（仓库不需要特殊处理）
// ---------------------------------------------------------------------------

#include "NFStorageBagOpMgr.h"

#include "NFOnlineAcc.h"
#include "proto_cs_cmd.nanopb.h"
#include "proto_event.nanopb.h"
#include "proto_event.pb.h"
#include "proto_svr_bag.pb.h"
#include "proto_svr_common.nanopb.h"
#include "NFComm/NFPluginModule/NFIEventModule.h"
#include "NFLogicCommon/BagPage/NFBagPageOp.h"

/**
 * @brief 构造函数
 * 
 * 功能说明：
 * 1. 调用基类构造函数，传入账号UID、操作原因和提交标志
 * 2. 保存账号指针
 * 3. 自动调用 AddAllBagPage() 添加仓库背包页签
 * 
 * @param pAcc 账号指针
 * @param iOpReason 操作原因
 * @param bNeedCommit 是否需要提交（默认true）
 */
NFStorageBagOpMgr::NFStorageBagOpMgr(NFOnlineAcc* pAcc, int iOpReason, bool bNeedCommit):NFBagPageOpMgrInterface(pAcc->GetUid(), iOpReason, bNeedCommit),m_pAcc(pAcc)
{
    AddAllBagPage();
}

/**
 * @brief 析构函数
 */
NFStorageBagOpMgr::~NFStorageBagOpMgr()
{
}

/**
 * @brief 提交所有操作
 * 
 * 功能说明：
 * 1. 检查账号指针有效性
 * 2. 调用 CommitToPlayer() 提交所有背包变更
 * 3. 如果需要同步，调用 SyncToPlayer() 同步到客户端
 * 4. 调用 Disgorgment() 进行预缴操作
 * 
 * @param bSyncToClient 是否将变更同步给客户端
 * @return 0成功，非0失败
 */
int NFStorageBagOpMgr::Commit(bool bSyncToClient)
{
    int iRetCode = 0;
    CHECK_NULL(m_ownerId, m_pAcc);

    iRetCode = CommitToPlayer();
    CHECK_ERR(m_ownerId, iRetCode, "Commit");

    if (bSyncToClient)
    {
        iRetCode = SyncToPlayer();
        CHECK_ERR_NT(m_ownerId, iRetCode, "SyncToPlayer");
    }

    // 进行预缴操作
    iRetCode = Disgorgment();
    CHECK_ERR_NT(m_ownerId, iRetCode, "Disgorgment");

    return 0;
}

/**
 * @brief 获取背包页签
 * 
 * 功能说明：
 * 1. 检查账号指针有效性
 * 2. 返回账号的仓库背包页签
 * 
 * @param iBagType 背包页签类型（仓库只有一个页签，此参数未使用）
 * @return 背包页签指针，失败返回nullptr
 */
NFBagPage* NFStorageBagOpMgr::GetBagPage(int iBagType)
{
    CHECK_NULL_RE_NULL(m_ownerId, m_pAcc, "");
    return m_pAcc->GetBagPage();
}

/**
 * @brief 添加所有背包页签
 * 
 * 功能说明：
 * 1. 检查账号指针有效性
 * 2. 创建页签类型列表，添加仓库页签类型（EN_BPT_STORAGE）
 * 3. 调用基类的 AddBagPageOp() 添加背包页签操作器
 * 
 * @return 0成功，非0失败
 */
int NFStorageBagOpMgr::AddAllBagPage()
{
    int iRetCode = 0;
    CHECK_NULL(0, m_pAcc);

    std::vector<int> vec;
    vec.push_back(EN_BPT_STORAGE);
    iRetCode = AddBagPageOp(vec);
    CHECK_ERR(m_ownerId, iRetCode, "AddBagPageOp");
    return 0;
}

/**
 * @brief 获取金钱数量
 * 
 * 功能说明：
 * 仓库不存储金钱，直接返回0
 * 
 * @param moneyType 金钱类型
 * @return 0（仓库不存储金钱）
 */
int64_t NFStorageBagOpMgr::GetMoneyNumber(int moneyType)
{
    return 0;
}

/**
 * @brief 设置金钱数量
 * 
 * 功能说明：
 * 仓库不支持金钱操作，返回错误码
 * 
 * @param moneyType 金钱类型
 * @param num 金钱数量
 * @return ERR_CODE_INVALID_REQ_PARAM（不支持）
 */
int NFStorageBagOpMgr::SetMoneyNumber(int moneyType, int64_t num)
{
    return ERR_CODE_INVALID_REQ_PARAM;
}

/**
 * @brief 增加金钱
 * 
 * 功能说明：
 * 仓库不支持金钱操作，返回错误码
 * 
 * @param enMoneyType 金钱类型
 * @param llMoney 想要增加的金钱数
 * @param pAddedNum 输出实际增加数量
 * @return ERR_CODE_INVALID_REQ_PARAM（不支持）
 */
int NFStorageBagOpMgr::IncMoney(int enMoneyType, int llMoney, int* pAddedNum)
{
    return ERR_CODE_INVALID_REQ_PARAM;
}

/**
 * @brief 减少金钱
 * 
 * 功能说明：
 * 仓库不支持金钱操作，返回错误码
 * 
 * @param enMoneyType 金钱类型
 * @param llMoney 想要减少的金钱数
 * @param piDelNum 输出实际减少数量
 * @return ERR_CODE_INVALID_REQ_PARAM（不支持）
 */
int NFStorageBagOpMgr::DecMoney(int enMoneyType, int llMoney, int* piDelNum)
{
    return ERR_CODE_INVALID_REQ_PARAM;
}

/**
 * @brief 背包满时添加物品的特殊处理
 * 
 * 功能说明：
 * 仓库满时不需要特殊处理（不像玩家背包那样发送邮件），直接返回成功
 * 
 * @param stWillAddItemData 待添加物品数据
 * @param iLeftAddNum 剩余要添加的数量
 * @param iAddNum 输出实际添加数量
 * @return 0成功
 */
int NFStorageBagOpMgr::AddItemWhenBagFull(const WillAddItemData& stWillAddItemData, int iLeftAddNum, int& iAddNum)
{
    return 0;
}

/**
 * @brief 背包满时添加物品的特殊处理（物品对象版本）
 * 
 * 功能说明：
 * 1. 检查物品指针有效性
 * 2. 仓库满时不需要特殊处理，直接返回成功
 * 
 * @param pItem 物品对象
 * @param iLeftAddNum 剩余要添加的数量
 * @param iAddNum 输出实际添加数量
 * @return 0成功
 */
int NFStorageBagOpMgr::AddItemWhenBagFull(const NFGridItem* pItem, int iLeftAddNum, int& iAddNum)
{
    CHECK_NULL(m_ownerId, pItem);
    return 0;
}

/**
 * @brief 提交所有操作到账号
 * 
 * 功能说明：
 * 1. 检查账号指针有效性
 * 2. 调用 PreCheckCommit() 进行预检查
 * 3. 清空物品操作记录
 * 4. 遍历所有背包页签操作器，调用其 Commit() 方法
 * 5. 调用 BaseCommit() 完成基类提交
 * 6. 标记账号为脏（需要保存）
 * 7. 遍历物品操作记录，触发物品增加/删除事件
 * 
 * @return 0成功，非0失败
 */
int NFStorageBagOpMgr::CommitToPlayer()
{
    int iRetCode = 0;
    CHECK_NULL(m_ownerId, m_pAcc);

    iRetCode = PreCheckCommit();
    CHECK_ERR(m_ownerId, iRetCode, "PreCheckCommit");

    m_opItemRec.clear();
    for (int i = 0; i < (int)m_allBagPageOps.size(); i++)
    {
        NFBagPageOp* pBagPageOp = m_allBagPageOps[i];
        if (pBagPageOp)
        {
            pBagPageOp->Commit(m_opItemRec);
        }
    }

    BaseCommit();
    m_pAcc->MarkDirty();

    proto_ff::EventPlayerItemAdd addEvent;
    addEvent.set_reason(m_enPackageOpReason);
    addEvent.set_from_mail(m_bFromMail);

    proto_ff::EventPlayerItemDel delEvent;
    delEvent.set_reason(m_enPackageOpReason);

    for (auto iter = m_opItemRec.begin(); iter != m_opItemRec.end(); ++iter)
    {
        LOG_TRACE(m_ownerId, "itemId:{} num:{}", iter->first, iter->second);
        if (iter->second > 0)
        {
            m_itemChangeRec[iter->first] = iter->second;
            addEvent.set_item_id(iter->first);
            addEvent.set_num(iter->second);
            FindModule<NFIEventModule>()->FireExecute(NF_ST_ONLINE_SERVER, EVENT_PLAYER_ITEM_ADD, EVENT_SRC_TYPE_PLAYER, m_ownerId, addEvent);
        }
        else if (iter->second < 0)
        {
            m_itemChangeRec[iter->first] = iter->second;
            delEvent.set_item_id(iter->first);
            delEvent.set_num(iter->second);
            FindModule<NFIEventModule>()->FireExecute(NF_ST_ONLINE_SERVER, EVENT_PLAYER_ITEM_DEL, EVENT_SRC_TYPE_PLAYER, m_ownerId, delEvent);
        }
    }
    return 0;
}

/**
 * @brief 将变更同步给客户端
 * 
 * 功能说明：
 * 1. 检查账号指针有效性
 * 2. 调用 SyncPackageToPlayer() 同步仓库背包变更
 * 
 * @return 0成功，非0失败
 */
int NFStorageBagOpMgr::SyncToPlayer()
{
    int iRetCode = 0;
    CHECK_NULL(m_ownerId, m_pAcc);

    iRetCode = SyncPackageToPlayer();
    CHECK_ERR_NT(m_ownerId, iRetCode, "SyncPackageToPlayer");

    return 0;
}

/**
 * @brief 预检查提交
 * 
 * 功能说明：
 * 1. 调用 BaseCommitCheck() 进行基类检查
 * 2. 检查是否已经提交过（禁止重复提交）
 * 3. 遍历所有背包页签操作器，调用其 PreCheckCommit() 方法
 * 
 * @return 0成功，非0失败
 */
int NFStorageBagOpMgr::PreCheckCommit()
{
    int iRetCode = 0;
    iRetCode = BaseCommitCheck();
    CHECK_ERR(m_ownerId, iRetCode, "BaseCommitCheck");

    if (m_bCommit) // 禁止重复提交
    {
        CHECK_ERR(m_ownerId, -1, "had commit");
    }

    for (int i = 0; i < (int)m_allBagPageOps.size(); i++)
    {
        NFBagPageOp* pBagPageOp = m_allBagPageOps[i];
        if (pBagPageOp)
        {
            iRetCode = pBagPageOp->PreCheckCommit();
            CHECK_ERR(m_ownerId, iRetCode, "PreCheckCommit");
        }
    }
    return 0;
}

/**
 * @brief 将仓库背包变更同步给客户端
 * 
 * 功能说明：
 * 1. 检查账号指针有效性
 * 2. 创建仓库物品变更通知消息
 * 3. 遍历所有背包页签操作器，填充物品变更信息
 * 4. 通过账号广播消息给所有角色
 * 
 * @return 0成功，非0失败
 */
int NFStorageBagOpMgr::SyncPackageToPlayer()
{
    CHECK_NULL(m_ownerId, m_pAcc);
    proto_ff::Proto_OnlineToLogicStorageItemChangeNtf respond;
    proto_ff::Proto_CSRoleItemNtf* pNtf = respond.mutable_item_list();
    for (int i = 0; i < (int)m_allBagPageOps.size(); i++)
    {
        NFBagPageOp* pBagPageOp = m_allBagPageOps[i];
        if (pBagPageOp)
        {
            pBagPageOp->FillPackageInfoNotify(pNtf, GetPackageOpReason());
        }
    }
    m_pAcc->BroadCast(E_SS_STORAGE_ITEM_CHANGE, respond);
    return 0;
}
